/*************************************************************************/ 
/** Copyright.                                                          **/
/** FileName: DemoProc.c                                                **/
/** Author: Polarix                                                     **/
/** Description: User operation interface.                              **/
/*************************************************************************/
//=======================================================================//
//= Include files.                                                      =//
//=======================================================================//
#include "DemoProc.h"
#include "SGUI_Basic.h"
#include <linux/input.h>

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/ipc.h>
#ifdef _SIMPLE_GUI_IN_VIRTUAL_SDK_
#include "simulator_if.h"
#include "SGUI_FontResource.h"
#else
#include "screen.h"
#include "kbdev.h"
//#include "usart.h"
///#include "rtc.h"
//#include "base_timer.h"
#include "DemoActions.h"
//#include "trigger_flags.h"
//#include "keyboard.h"
#endif

//=======================================================================//
//= Macro definition.                                                   =//
//=======================================================================//
#define BMP_DATA_BUFFER_SIZE    (512)
#define MQ_KEYT_PATHNAME "/app/m1100app"
#define MQ_KEYT_PROJID 0x4262

//=======================================================================//
//= Static variable declaration.   20251104 放到这里 才可以在菜单界面加载进去=//
//=======================================================================//
SGUI_SCR_DEV                g_stDeviceInterface;
HMI_SCREEN_OBJECT*          g_arrpstScreenObjs[] =
                            {
                                &g_stHMIDemo_List,
                                // &g_stHMIDemo_TextPaint,
                                // &g_stHMIDemo_VariableBox,
                                // &g_stHMIDemo_RealtimeGraph,
                                // &g_stHMIDemo_Menu,
                                // &g_stHMIDemo_Notice,
                                // &g_stHMIDemo_BasicPaint,
                                // &g_stHMIDemo_Curve,
                                // &g_stHMIDemo_PolorCoord,
                                &g_stHMIMeasureBPaint,
                                &g_stHMIMeasureAPaint,
                                &g_stHMICalibratePaint,
                                &g_stHMISet_Menu
                            };
HMI_ENGINE_OBJECT           g_stDemoEngine;

SGUI_BYTE                   s_pBmpDataBuffer[BMP_DATA_BUFFER_SIZE];


// communication to app
// static key_t key;
static unsigned int         s_uiKeyValue;
// 20251023 global leq data
char time_str[64];
char battery_str[3];
LEQ_DATA_EVENT_DATA  LeqData;
key_t key;
int msgqid;

//=======================================================================//
//= Static function declare.                                            =//
//=======================================================================//
static void                 KeyPressEventProc(void);
static void                 EnterScreen(void);
static void                 AppPressEventProc(void);
static void                 RTCEventProc(void);
static void                 SysTickTimerEventProc(void);


//=======================================================================//
//= Function define.                                                    =//
//=======================================================================//


void alarm_handler(int signum)
{
    printf("Alarm, Signal number:%d\n", signum);
}

/*****************************************************************************/
/** Function Name:  InitializeHMIEngineObj                                  **/
/** Purpose:        Simple GUI HMI engine and interface demo process.       **/
/** Parameters:     None.                                                   **/
/** Return:         HMI_ENGINE_RESULT.                                      **/
/** Notice:         This function demonstrates how to use the interface and **/
/**                 HMI engine of Simple GUI.                               **/
/*****************************************************************************/
HMI_ENGINE_RESULT InitializeHMIEngineObj(void)
{
    /*----------------------------------*/
    /* Variable Declaration             */
    /*----------------------------------*/
    HMI_ENGINE_RESULT           eProcessResult;
    int                         iIndex;

    /*----------------------------------*/
    /* Initialize                       */
    /*----------------------------------*/
    eProcessResult =            HMI_RET_NORMAL;

    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
    /* Clear structure. */
    SGUI_SystemIF_MemorySet(&g_stDeviceInterface, 0x00, sizeof(SGUI_SCR_DEV));
    SGUI_SystemIF_MemorySet(&g_stDemoEngine, 0x00, sizeof(HMI_ENGINE_OBJECT));
#ifdef _SIMPLE_GUI_IN_VIRTUAL_SDK_
    /* Initialize display size. */
    g_stDeviceInterface.stSize.iWidth = 128;
    g_stDeviceInterface.stSize.iHeight = 64;
    /* Initialize interface object. */
    g_stDeviceInterface.fnSetPixel = simulator_if_paint_pixel;
#ifdef SGUI_GET_POINT_FUNC_EN
    g_stDeviceInterface.fnGetPixel = simulator_if_read_pixel;
#endif // SGUI_GET_POINT_FUNC_EN
    //g_stDeviceInterface.fnFillRect = SGUI_SDK_FillRectangle;
    g_stDeviceInterface.fnClear = simulator_if_clear_screen;
    g_stDeviceInterface.fnSyncBuffer = simulator_if_flush_screen;
#else
    g_stDeviceInterface.stSize.iWidth = LCD_SIZE_WIDTH;
    g_stDeviceInterface.stSize.iHeight = LCD_SIZE_HEIGHT;
   // #error Add screen device object initialize process here.
    g_stDeviceInterface.fnSetPixel = SCREEN_SetPixel;
    //g_stDeviceInterface.fnGetPixel = SCREEN_GetPixel;
    g_stDeviceInterface.fnClear =SCREEN_ClearDisplay;
    g_stDeviceInterface.fnSyncBuffer = SCREEN_RefreshScreen;
#endif
    g_stDeviceInterface.stBuffer.pBuffer = s_pBmpDataBuffer;
    g_stDeviceInterface.stBuffer.sSize = BMP_DATA_BUFFER_SIZE;

    // signal(SIGALRM, alarm_handler);
    // TIMER 
    // alarm(1);
    // printf("set alarm\n");

    SGUI_Basic_ResetMask(&g_stDeviceInterface);
    do
    {
        /* Prepare HMI engine object. */
        g_stDemoEngine.ScreenCount = sizeof(g_arrpstScreenObjs)/sizeof(*g_arrpstScreenObjs);
        g_stDemoEngine.ScreenObjPtr = g_arrpstScreenObjs;
        g_stDemoEngine.Interface = &g_stDeviceInterface;

        printf("screen count=%d\n",g_stDemoEngine.ScreenCount );

        /* Initialize all screen object. */
        if(NULL != g_stDemoEngine.ScreenObjPtr)
        {
            for(iIndex=0; iIndex<g_stDemoEngine.ScreenCount; iIndex++)
            {
                if( (NULL != g_stDemoEngine.ScreenObjPtr[iIndex])
                    && (NULL != g_stDemoEngine.ScreenObjPtr[iIndex]->pstActions)
                    && (NULL != g_stDemoEngine.ScreenObjPtr[iIndex]->pstActions->Initialize)
                    )
                {
                    g_stDemoEngine.ScreenObjPtr[iIndex]->pstActions->Initialize(&g_stDeviceInterface);
                    g_stDemoEngine.ScreenObjPtr[iIndex]->pstPrevious = NULL;
                }
            }
        }
        else
        {
        }
        /* Active engine object. */
        eProcessResult = HMI_ActiveEngine(&g_stDemoEngine, HMI_SCREEN_ID_DEMO_LIST);
        if(HMI_PROCESS_FAILED(eProcessResult))
        {
            /* Active engine failed. */
            break;
        }
        /* Start engine process. */
        eProcessResult = HMI_StartEngine(NULL);
        if(HMI_PROCESS_FAILED(eProcessResult))
        {
            /* Start engine failed. */
            break;
        }
    }while(0);

    return eProcessResult;
}

/*****************************************************************************/
/** Function Name:  DemoMainProcess                                         **/
/** Purpose:        It is a dummy main function for SimpleGUI Virtual SDK,  **/
/**                 or run demo process in demo process.                    **/
/** Parameters:     None.                                                   **/
/** Return:         Terminal code, seam as main function return code.       **/
/** Notice:         None.                                                   **/
/*****************************************************************************/
void DemoMainProcess(void)
{
    /*----------------------------------*/
    /* Initialize                       */
    /*----------------------------------*/

    /* init communication */
    key = ftok(MQ_KEYT_PATHNAME, MQ_KEYT_PROJID);
    if (key < 0)
    {
        printf("%s:%d key:%d \n", __FILE__,__LINE__, key);
    }
    msgqid = msgget(key, IPC_CREAT | 0660); // nerver delete Q until reboot
    if (msgqid < 0)
    {
        printf("%s:%d msgqid:%d \n", __FILE__,__LINE__, key);
    }
    printf("%s:%d key:%x msgqid:%d\n", __FILE__,__LINE__, key, msgqid);


    // Initialize HMI Engine.
    InitializeHMIEngineObj();

    // enter first screen; first screen donot is menu
    EnterScreen();

    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
    while(1)
    {
        // 1. get systime
        time_t now_sec;
        time(&now_sec); // 等价于 now_sec = time(NULL);

        // 2. 转换为本地时间（结构体，包含年月日时分秒）
        struct tm *local_time = localtime(&now_sec);
        if (local_time == NULL) 
        {
            perror("localtime failed");
            return -1;
        }
        // 3. 格式化输出（年-月-日 时:分:秒）
        // strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", local_time);
        strftime(time_str, sizeof(time_str), "%H:%M:%S", local_time);
        //printf("aa本地时间（秒级）: %s\n", time_str);

        //simulator_ticks_prolog();
        // Check and process heart-beat timer event.
        // if(true == SysTickTimerTriggered())
        // {
           
        //     SysTickTimerEventProc();
        // }
       // Check and process key press event.
        if(true == UserEventTriggered())
        {
            //printf("use key time=%s\n",time_str);
            KeyPressEventProc();
        }
        // // // Check and process RTC event.
        // if(true == RTCTimerTriggered())
        // {
        //     RTCEventProc();
        // }

        if(true == AppEventTriggered())
        {
            //printf("app event time=%s\n",time_str);
            AppPressEventProc();

            //HMI_ProcessEvent((HMI_EVENT_BASE*)(&stEvent));
            //g_stDemoEngine.ScreenObjPtr[1]->pstActions->ProcessEvent() ;
        }
    }
}

/*****************************************************************************/
/** Function Name:  KeyPressEventProc                                       **/
/** Purpose:        Deal with user key process in demo process.             **/
/** Parameters:     None.                                                   **/
/** Return:         None.                                                   **/
/** Notice:         The button is just abstract, and the message may come   **/
/**                 from a touch screen, a serial port, and so on.          **/
/*****************************************************************************/
void KeyPressEventProc(void)
{
    /*----------------------------------*/
    /* Variable Declaration             */
    /*----------------------------------*/
    KEY_PRESS_EVENT         stEvent;

    /*----------------------------------*/
    /* Initialize                       */
    /*----------------------------------*/
    HMI_EVENT_INIT(stEvent);

    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
    stEvent.Head.iID = EVENT_ID_KEY_PRESS;
    //stEvent.Head.iSize = SGUI_TRUE;
#ifdef _SIMPLE_GUI_IN_VIRTUAL_SDK_
    stEvent.Data.uiKeyValue = simulator_if_read_key();
#else
    //#error Add key event data prepare process here.
#endif
    stEvent.Data.uiKeyValue = s_uiKeyValue;

    printf("%s:%d key press kv=%d headsize=%d\n",__FILE__, __LINE__, stEvent.Data.uiKeyValue, stEvent.Head.iSize);
    // Post key press event.
    HMI_ProcessEvent((HMI_EVENT_BASE*)(&stEvent));
}

/*****************************************************************************/
/** Function Name:  EnterScreen                                             **/
/** Purpose:        enter first Measure ui when system start up.            **/
/** Parameters:     None.                                                   **/
/** Return:         None.                                                   **/
/** Notice:         The button is just abstract, and no message come in     **/
/**                 just for init first screen.                             **/
/*****************************************************************************/
void EnterScreen(void)
{
    /*----------------------------------*/
    /* Variable Declaration             */
    /*----------------------------------*/
    KEY_PRESS_EVENT         stEvent;

    /*----------------------------------*/
    /* Initialize                       */
    /*----------------------------------*/
    HMI_EVENT_INIT(stEvent);

    /*----------------------------------*/
    /* Process   define screen by uiKeyValue*/
    /*----------------------------------*/
    stEvent.Head.iID = EVENT_ID_KEY_PRESS;
    stEvent.Data.uiKeyValue = 13;       
    stEvent.Head.iSize = 12;

    printf("%s:%d key press kv=%d headsize=%d\n",__FILE__, __LINE__, stEvent.Data.uiKeyValue, stEvent.Head.iSize);
    // Post key press event.
    HMI_ProcessEvent((HMI_EVENT_BASE*)(&stEvent));
}


/*****************************************************************************/
/** Function Name:  AppPressEventProc                                       **/
/** Purpose:        Deal with user app process in demo process.             **/
/** Parameters:     None.                                                   **/
/** Return:         None.                                                   **/
/** Notice:                                                                 **/
/*****************************************************************************/
void AppPressEventProc(void)
{
    /*----------------------------------*/
    /* Variable Declaration             */
    /*----------------------------------*/
    LEQ_EVENT         stEvent;

    /*----------------------------------*/
    /* Initialize                       */
    /*----------------------------------*/
    HMI_EVENT_INIT(stEvent);

    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
    ghdMessage_t msg;
    msg.type = 1;
    while(msgrcv(msgqid, (void*)&msg, GHDMESS_SIZE, 1, IPC_NOWAIT) != -1)
    {
        LeqData.uLeqA = msg.fleq1 * 10;
        LeqData.uLeqC = msg.fleq2 * 10;
        LeqData.uLeqZ = msg.fleq3 * 10;

        // ui o调整fs  hold下个版本增加
        //LeqData.uWeightType = msg.fs;
        //LeqData.uHoldStatus = msg.hold;
        // LeqData.uWeightType = msg.fs;  // get all acz data; this vairable come from ui
        // printf("20241027 receive app data:%.1f %.2f %.3f fs=%d\n", msg.fleq1, msg.fleq2, msg.fleq3,LeqData.uWeightType);
    }

    GetBatteryValue();

    stEvent.Head.iID = EVENT_ID_LEQ;

    // get charge status
    LeqData.uChargeStatus = 1;

    HMI_EVENT_BASE  *aa = (HMI_EVENT_BASE*)(&stEvent);
    // printf("test aa \n", aa->iID, stEvent.Data.uLeqA);
    // printf("test aa \n", aa->iID, aa->iSize);

    // Post key press event.
    HMI_ProcessEvent((HMI_EVENT_BASE*)(&stEvent));
}

/*****************************************************************************/
/** Function Name:  SysTickTimerEventProc                                   **/
/** Purpose:        Deal with heartbeat timer event in demo process.        **/
/** Parameters:     None.                                                   **/
/** Return:         None.                                                   **/
/** Notice:         It is usually used to simulate ADC or other sensors.    **/
/*****************************************************************************/
void SysTickTimerEventProc(void)
{
    printf("SysTickTimerEventProc\n");
    /*----------------------------------*/
    /* Variable Declaration             */
    /*----------------------------------*/
    DATA_EVENT              stEvent;

    /*----------------------------------*/
    /* Initialize                       */
    /*----------------------------------*/
    HMI_EVENT_INIT(stEvent);

    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
    stEvent.Head.iID = EVENT_ID_TIMER;
    stEvent.Data.iValue = (rand() % 200)-100;
    // Post timer event.
    HMI_ProcessEvent((HMI_EVENT_BASE*)&stEvent);
}

/*****************************************************************************/
/** Function Name:  RTCEventProc                                            **/
/** Purpose:        Deal with RTC timer event in demo process.              **/
/** Parameters:     None.                                                   **/
/** Return:         None.                                                   **/
/** Notice:         It is usually used to simulate ADC or other sensors.    **/
/*****************************************************************************/
void RTCEventProc(void)
{
    /*----------------------------------*/
    /* Variable Declaration             */
    /*----------------------------------*/
    HMI_GENERAL_EVENT       stEvent;

    /*----------------------------------*/
    /* Initialize                       */
    /*----------------------------------*/
    HMI_EVENT_INIT(stEvent);

    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
    stEvent.Head.iID =      EVENT_ID_RTC;
    // Post RTC update message to a screen.
    HMI_ProcessEvent((HMI_EVENT_BASE*)&stEvent);
}

/*****************************************************************************/
/** Function Name:  SysTickTimerTriggered                                   **/
/** Purpose:        Check sys-tick timer interrupt is triggered.            **/
/** Parameters:     None.                                                   **/
/** Return:         None.                                                   **/
/** Notice:         None.                                                   **/
/*****************************************************************************/
bool SysTickTimerTriggered(void)
{
    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
#ifdef _SIMPLE_GUI_IN_VIRTUAL_SDK_
    return simulator_if_has_data();
#else
    // 简单测试，模拟定时器触发
    static int tick_counter = 0;
    tick_counter++;
    if(tick_counter >= 500) { // 每隔一定次数触发一次
        tick_counter = 0;
        return true;
    }
    return false;
#endif
}

/*****************************************************************************/
/** Function Name:  RTCTimerTriggered                                       **/
/** Purpose:        Check RTC timer interrupt is triggered.                 **/
/** Parameters:     None.                                                   **/
/** Return:         None.                                                   **/
/** Notice:         None.                                                   **/
/*****************************************************************************/
bool RTCTimerTriggered(void)
{
    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
#ifdef _SIMPLE_GUI_IN_VIRTUAL_SDK_
    return simulator_if_rtc_update();
#else
    // // Add Dummy RTC trigger process here.
    return true;
#endif
}

/*****************************************************************************/
/** Function Name:  UserEventTriggered                                      **/
/** Purpose:        Check user event is triggered.                          **/
/** Parameters:     None.                                                   **/
/** Return:         None.                                                   **/
/** Notice:         None.                                                   **/
/*****************************************************************************/
// bool UserEventTriggered(void)
// {
//     /*----------------------------------*/
//     /* Process                          */
//     /*----------------------------------*/
// #ifdef _SIMPLE_GUI_IN_VIRTUAL_SDK_
//     return simulator_if_has_key_event();
// #else
//    // #error Add user event trigger process here.
// #endif
//         char ch = getchar();
//         if (ch == 'u' || ch == 'U') {
//             s_uiKeyValue = 0x013D; // 上键
//             return true;
//         } else if (ch == 'd' || ch == 'D') {
//             s_uiKeyValue = 0x013E; // 下键
//             return true;
//         }
//     return false;
// }
// 修改 UserEventTriggered 函数
#include <sys/select.h>
#include <unistd.h>
bool UserEventTriggered(void)
{
#ifdef _SIMPLE_GUI_IN_VIRTUAL_SDK_
    return simulator_if_has_key_event();
#else
     /*----------------------------------*/
    /* Variable Declaration             */
    /*----------------------------------*/
    KBDEV_KEY_INFO stKeyInfo;
    int iResult;
    
    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
    // 使用KBDEV_ReadKey_Timeout读取按键信息，设置50ms超时
    iResult = KBDEV_ReadKey_Timeout(&stKeyInfo);

    // 检查是否有按键事件  and  keytype is pressed
    if (iResult == 1)
    {
        // 有按键事件  20251027 iEventType=0:press  1:release
        if (stKeyInfo.iEventType == KBDEV_EVENT_RELEASE) 
        {
            printf("%s:%d get key type=%d keyv=%d\n",__FILE__, __LINE__, stKeyInfo.iEventType, stKeyInfo.uiKeyValue);
    
            // 只处理按键按下事件
            s_uiKeyValue = stKeyInfo.uiKeyValue;
            return true;
        }
    } 
    else if (iResult < 0) 
    {
        // 发生错误
        printf("Error reading key event\n");
    }
    
    // 没有按键事件或发生错误
    return false;
#endif
}


/*****************************************************************************/
/** Function Name:  AppEventTriggered                                       **/
/** Purpose:        app message received.                                   **/
/** Parameters:                                                             **/
/** @ bEnable[in]:                                                          **/
/** Return:         None.                                                   **/
/** Notice:         None.                                                   **/
/*****************************************************************************/
bool AppEventTriggered(void)
{
    // sleep(1);
    return true;
}

/*****************************************************************************/
/** Function Name:  SysTickTimerEnable                                      **/
/** Purpose:        Enable or disable sys-tick timer.                       **/
/** Parameters:                                                             **/
/** @ bEnable[in]:  True for enable sys-tick timer, false for disable.      **/
/** Return:         None.                                                   **/
/** Notice:         None.                                                   **/
/*****************************************************************************/
void SysTickTimerEnable(bool bEnable)
{
    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
#ifdef _SIMPLE_GUI_IN_VIRTUAL_SDK_
    // (void)SGUI_SDK_ConfigGeneralTimer(bEnable?DEMO_HEART_BEAT_INTERVAL_MS:0);
#else
   // #error Add sys-tick timer enable/disable process here.
#endif
}

/*****************************************************************************/
/** Function Name:  RTCTimerEnable                                          **/
/** Purpose:        Enable or disable RTC timer.                            **/
/** Parameters:                                                             **/
/** @ bEnable[in]:  True for enable RTC timer, false for disable.           **/
/** Return:         None.                                                   **/
/** Notice:         None.                                                   **/
/*****************************************************************************/
void RTCTimerEnable(bool bEnable)
{

    /*----------------------------------*/
    /* Process                          */
    /*----------------------------------*/
#ifdef _SIMPLE_GUI_IN_VIRTUAL_SDK_
    // (void)SGUI_SDK_EnableSecondInterrupt(bEnable);
#endif
}


SGUI_UINT GetBatteryValue(void)
{
    FILE *fp;
    int capacity = -1;
    char buffer[48];
    SGUI_UINT n_battery_value = 0;

    // 打开/proc/capacity文件
    fp = fopen("/sys/class/power_supply/battery/capacity", "r");
    if (fp == NULL)
    {
        perror("can not open /sys/class/power_supply/battery/capacity");
        return -1;
    }

    // 读取文件内容
    if (fgets(buffer, sizeof(buffer), fp) == NULL)
    {
        perror("fgets(buffer) error.");
        fclose(fp);
        return;
    }

    // 关闭文件
    fclose(fp);

    // 将字符串转换为长整型数值
    //errno = 0;
    capacity = strtol(buffer, NULL, 10);
    //if (errno != 0)
    //{
    //    perror("strtol(buffer) error.");
    //    return;
    //}

    if (capacity > -1)
    {
        /*电量取5的位数向上取整数,解决电量显示 一直充不满的问题 */
        n_battery_value = (capacity / 5 + 1) * 5;
        n_battery_value = (n_battery_value > 100) ? 100 : n_battery_value;
    }
    else
    {
        n_battery_value = 0;
    }

    int ret = snprintf(battery_str, sizeof(battery_str), "%d", n_battery_value);
    if(ret < 0)
    {
        printf("change n_battery_value to char error.\n");
    }
    return n_battery_value;
}

